﻿using System;
using System.Collections;
using System.Collections.Generic;

using System.Reflection;
using WoChu.CF.BaseFrame.Util;
using System.Text;
namespace WoChu.CF.BaseFrame.Json
{
    /// <summary>
    /// JsonDeserializer
    /// </summary>
    public class JsonDeserializer
    {
        private static readonly Type _IListType = typeof(IList);
        private readonly JsonReader _reader;
        private readonly string _fieldPrefix;
         
        /// <summary>
        /// JsonDeserializer
        /// </summary>
        /// <param name="reader"></param>
        public JsonDeserializer(JsonReader reader) : this(reader, string.Empty){}
        /// <summary>
        /// JsonDeserializer
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="fieldPrefix"></param>
        public JsonDeserializer(JsonReader reader, string fieldPrefix)
        {
            _reader = reader;
            _fieldPrefix = fieldPrefix;
        }
        /// <summary>
        /// Deserialize
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static T Deserialize<T>(JsonReader reader)
        {
            return Deserialize<T>(reader, string.Empty);
        }
        /// <summary>
        /// Deserialize
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reader"></param>
        /// <param name="fieldPrefix"></param>
        /// <returns></returns>
        public static T Deserialize<T>(JsonReader reader, string fieldPrefix)
        {
            return (T) new JsonDeserializer(reader, fieldPrefix).deserializeValue(typeof(T));
        }
 

        #region 内部函数处理...
        private object deserializeValue(Type type)
        {
            _reader.SkipWhiteSpaces();            
            if (type == typeof(int))
            {
                return _reader.ReadInt32();                
            }
            else if (type == typeof(bool))
            {
                return _reader.ReadBool();
            }
            else if (type == typeof(string))
            {
                return _reader.ReadString();                
            }
            else if (type == typeof(double))
            {
                return _reader.ReadDouble();
            }
            else if (type == typeof(DateTime))
            {
                return _reader.ReadDateTime();
            }
            else if (_IListType.IsAssignableFrom(type))
            {
                return deserializeList(type);
            }            
            else if (type == typeof(char))
            {
                return _reader.ReadChar();
            }
            else if (type.IsEnum)
            {
                return _reader.ReadEnum();
            }
            else if (type == typeof(long))
            {
                return _reader.ReadInt64();
            }        
            else if (type == typeof(float))
            {
                return _reader.ReadFloat();
            }
            else if (type == typeof(short))
            {
                return _reader.ReadInt16();
            }
            else if (type == typeof(decimal))
            {
                return _reader.ReadDecimal(); 
            }
            return parseObject(type);            
        }

        private object deserializeList(Type listType)
        {
            _reader.SkipWhiteSpaces();
            //add by aifang check null list 2011-09-28 begin
            char p = _reader.Peek();
            if (p == JsonTokens.NULL_STRING_START)
            {
                StringBuilder sb = new StringBuilder(25);
                while (true)
                {
                    char c = _reader.Read();
                    sb.Append(c);
                    if (c == 'l' && sb.Length == JsonTokens.NULL_VALUE_LENGTH)
                    {
                        break;
                    }
                }
                if (sb.Length == JsonTokens.NULL_VALUE_LENGTH && sb.ToString() == JsonTokens.NULL_STRING)
                {
                    return null;
                }
            }
            //add by aifang check null list 2011-09-28 end
 
            _reader.AssertAndConsume(JsonTokens.START_ARRAY_CHARACTER);
            Type itemType = ListHelper.GetListItemType(listType);
            bool isReadonly;
            IList container = ListHelper.CreateContainer(listType, itemType, out isReadonly);
            while (true)
            {
                _reader.SkipWhiteSpaces();
                var item = deserializeValue(itemType);
                container.Add(item);
                _reader.SkipWhiteSpaces();
                if (_reader.AssertNextIsDelimiterOrSeparator(JsonTokens.END_ARRAY_CHARACTER))
                {
                    break;
                }
            }
            if (listType.IsArray)
            {
                return ListHelper.ToArray((List<object>)container, itemType);
            }
            if (isReadonly)
            {
                return listType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[] { container.GetType() }, null).Invoke(new object[] { container });
            }
            return container;
        }
        private object parseObject(Type type)
        {
            _reader.SkipWhiteSpaces();

            char p = _reader.Peek();
            if (p == JsonTokens.NULL_STRING_START)
            {
                StringBuilder sb = new StringBuilder(25);
                while (true)
                {
                    char c = _reader.Read();
                    sb.Append(c);
                    if (c == 'l' && sb.Length == JsonTokens.NULL_VALUE_LENGTH)
                    {
                        break;
                    }
                }
                if (sb.Length == JsonTokens.NULL_VALUE_LENGTH && sb.ToString() == JsonTokens.NULL_STRING)
                {
                    return null;
                }
            }

            _reader.AssertAndConsume(JsonTokens.START_OBJECT_LITERAL_CHARACTER);
            ConstructorInfo constructor = ReflectionHelper.GetDefaultConstructor(type);
            object instance = constructor.Invoke(null);
            while (true)
            {
                _reader.SkipWhiteSpaces();
                string name = _reader.ReadString();
                if (!name.StartsWith(_fieldPrefix))
                {
                    name = _fieldPrefix + name;
                }
                PropertyInfo proInfo = ReflectionHelper.FindProperty(type, name);
               
                _reader.SkipWhiteSpaces();
                _reader.AssertAndConsume(JsonTokens.PAIR_SEPARATOR);                
                _reader.SkipWhiteSpaces();
                 if(proInfo!=null) 
                    proInfo.SetValue(instance, deserializeValue(proInfo.PropertyType),null);

                _reader.SkipWhiteSpaces();
                if (_reader.AssertNextIsDelimiterOrSeparator(JsonTokens.END_OBJECT_LITERAL_CHARACTER))
                {
                    break;
                } 
            }
            return instance;
        }
        #endregion
    }
}